<?php

class Quad_Data_Cc extends Quad_Data_Abstract {
	
	public $number;
	public $matcher15 = '/^(\d{4})\D*(\d{6})\D*(\d{5})$/';
	public $matcher16 = '/^(\d{4})\D*(\d{4})\D*(\d{4})\D*(\d{4})$/';
	
	public function __construct($no = '') {
		$this->raw = $no;
		$this->number = trim($no);
	}
	
	public static function create($no) {
		return new self($no);
	}
	
	public function isValid() {
		return (
			$this->isSupportedType() &&
			$this->hasValidFormat() &&
			$this->hasValidChecksum()
		);
	}
	
	public function isSupportedType() {
		return in_array($this->getType(), $this->getSupportedTypes());
	}
	
	public function hasValidChecksum() {
		$digits = $this->digitsOnly();
		$digits = str_split($digits);
		$total = 0;
		foreach ($digits as $i => $digit) {
			if (($i % 2) == 0) {
				$total += (int) $digit * 2;
			}
			else {
				$total += (int) $digit;
			}
		}
		$isValid = (($total % 10) == 0);
		return $isValid;
	}
	
	public function hasValidFormat() {
		$formatOk = (
			($this->getType() == 'amex' && preg_match($this->matcher15, $this->number)) ||
			($this->getType() != 'amex' && preg_match($this->matcher16, $this->number))
		);
		return $formatOk;
	}
	
	public function digitsOnly() {
		return preg_replace('/\D/', '', $this->number);
	}
	
	public function format($mask = false) {
		if ($this->getType() == 'amex') {
			if (preg_match($this->matcher15, $this->number, $m)) {
				if ($mask) {
					$m[1] = 'XXXX';
					$m[2] = 'XXXXXX';
					$m[3] = 'X' . substr($m[3],1);
				}
				return "{$m[1]}-{$m[2]}-{$m[3]}";
			}
		}
		elseif (preg_match($this->matcher16, $this->number, $m)) {
			if ($mask) {
				$m[1] = $m[2] = $m[3] = 'XXXX';
			}			
			return "{$m[1]}-{$m[2]}-{$m[3]}-{$m[4]}";
		}
		return $this->number;
	}
	
	public function getType() {
		switch (true) {
			case substr($this->number,0,4) == '6011':
				return 'disc';
				
			case substr($this->number,0,1) == '4':
				return 'visa';
				
			case substr($this->number,0,1) == '5':
				return 'mc';
				
			default:
				$two = (int) substr($this->number,0,2);
				if ($two >= 34 && $two <= 37) {
					return 'amex';
				}
		}
		return false;
	}
	
	public function getSupportedTypes() {
		return array(
			'amex', 'mc', 'disc', 'visa'
		);
	}
	
}